#include<iostream>
#include<string>
#include<unistd.h>
#include<sys/types.h>
#include<cstdlib>
#include<vector>
#include<functional>
#include<sys/wait.h>
#include "Task.hpp"
#include "Channel.hpp"
using namespace std;

using work_t=function<void()>;//类似于typedef function<void()> work_t;


enum
{
	OK=0,
	UsageError,
	PipeError,
	ForkError
};

class ProcessPool
{

	public:
		ProcessPool(int n ,work_t w):processnum(n),work(w)
		{}

void DebugPrint()
{
	int i=0;
	for(auto & c:channels )
	{
		i++;
		cout<<i<<" "<<c.Name()<<"你好"<<endl;
	}
}



//channels:输出型参数
//work_t work 回调方法实际就是把拥有相同的函数类型但是不同参数函数名的函数包装起来了。
int InitProcesspol()
{	
	//创建指定个数进程。
	for(int i=0;i<processnum;i++)
        {
                //1.先有管道
                int pipefd[2]={0};//但是每一次循环都会将这个释放所以我们就要用到Channel了。
                int n=pipe(pipefd);
                if(n<0)
                {
                        cout<<"pipe false"<<endl;
                        return PipeError;
                }
                //2.创建子进程
                pid_t id=fork();
                if(id<0)return ForkError;
                //3.建立信道
                if(id==0)//子进程
                {
			cout<<getpid()<<", child close history fd :"<< endl;
			//关闭历史wfd
			for(auto & c :channels)
			{
				cout<< c.wfd()<<",";
				c.Close();
			}

			cout<<" over"<<endl;
			::close(pipefd[1]);
                        dup2(pipefd[0],0);
                        work();
                        ::exit(0);//结束就需要子进程退出了
                }
                //父进程执行
                ::close(pipefd[0]);
                channels.emplace_back(pipefd[1],id);//存取父进程的所有写端。
                //Channel ch(pipefd[1],id);
                //channels.push_back(ch);
        }
	return OK;
}

void DispatchTasks1()
{
	int num=20;
	int who=0;
	//2.派发任务。
	while(num--)
	{
		//a.随机的选择一个任务模拟任务的选择，整数。
		int task = tm1.SelectTask();
		//b.选择一个子进程channel
		//这里实现的是轮询的方式去选择进程
		Channel &curr=channels[who++];
		who %=channels.size();
		
		cout<<" ########### "<<endl;
		cout<<" send "<< task<<" to "<<curr.Name()<<" , 任务还剩 "<<num<<endl;
		//cout<<" 时间 "<<time(nullptr)<<endl;
		//c.派发任务
		curr.Send(task);
		cout<<" ########### "<<endl;
		sleep(2);
	}

}

void CleanProcessPol()
{
	
	//vesion1
	//
	//for(auto &c : channels)
	//{
	//	c.Close();
	//}

	//4.最后回收子进程
	//for( auto &c : channels)
	//{
	//	pid_t rid = ::waitpid(c.ID(),nullptr,0);
	//	if(rid>0)
	//		cout<<" child- "<<rid <<" -wait..success "<<endl;
	//}
	
	//vesion2	
	//缺点进程会回收不干净具体原因看笔记进程间的通信
        //for(auto &c : channels)
        //{
        //      c.Close();
	//        pid_t rid = ::waitpid(c.ID(),nullptr,0);
        //      if(rid>0)
        //              cout<<" child- "<<rid <<" -wait..success "<<endl;

        //}



	//vesion3
	//for(int i= channels.size()-1;i>=0;i--)
        //{
        //     channels[i].Close();
	//
        //      pid_t rid = ::waitpid(channels[i].ID(),nullptr,0);
        //      if(rid>0)
        //              cout<<" child- "<<rid <<" -wait..success "<<endl;
        //}

	//vesion4
	//我想从前往后关一个等待一个怎么办呢
	for(auto &c : channels)
        {
              c.Close();
              pid_t rid = ::waitpid(c.ID(),nullptr,0);
              if(rid>0)
                     cout<<" child- "<<rid <<" -wait..success "<<endl;
        }
}
private:
	vector<Channel>  channels;
	int processnum;
	work_t work;
};

